package com.xcity.game.battle.pve;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xcity.db.entity.Employee;
import com.xcity.db.entity.Player;
import com.xcity.db.entity.Ranking;
import com.xcity.game.ISystem;
import com.xcity.game.battle.BattleException;
import com.xcity.game.battle.pve.template.StageAreaTemplate;
import com.xcity.game.battle.pve.template.StagePageTemplate;
import com.xcity.game.battle.pve.template.StageTemplate;
import com.xcity.game.buycount.BuyCount;
import com.xcity.game.combat.CombatService;
import com.xcity.game.common.Cause;
import com.xcity.game.common.Currency;
import com.xcity.game.common.MessageConst;
import com.xcity.game.employee.skill.EmployeeSkill;
import com.xcity.game.event.GameEvents;
import com.xcity.game.formation.Formation;
import com.xcity.game.item.DropGroupTemplate;
import com.xcity.game.item.ItemInfo;
import com.xcity.game.item.ItemTemplate;
import com.xcity.game.item.drop.Drop;
import com.xcity.game.item.drop.DropGroup;
import com.xcity.game.item.drop.WeightDrop;
import com.xcity.game.item.drop.impl.ItemDrop;
import com.xcity.game.rank.RankingList;
import com.xcity.game.rank.RankingListEnum;
import com.xcity.game.shop.ShopItemTemplate;
import com.xcity.game.vip.VipUtils;
import com.xcity.pomelo.PomeloRoute;
import com.xcity.pomelo.request.PVEAttackRequest;
import com.xcity.pomelo.request.PVEBeAttackedRequest;
import com.xcity.pomelo.request.PVEFullRequest;
import com.xcity.pomelo.request.PVEGetAllBoxRequest;
import com.xcity.pomelo.request.PVEGetStageBoxRequest;
import com.xcity.pomelo.request.PVEGetStarBoxRequest;
import com.xcity.pomelo.request.PVEMoveBlockRequest;
import com.xcity.pomelo.request.PVEStageAreaRequest;
import com.xcity.pomelo.request.PVEStageBoxInfoRequest;
import com.xcity.pomelo.request.PVEStageBuyItemRequest;
import com.xcity.pomelo.request.PVEStageFightBeginRequest;
import com.xcity.pomelo.request.PVEStageFightEndRequest;
import com.xcity.pomelo.request.PVEStageFightGoOnRequest;
import com.xcity.pomelo.request.PVEStageFightPauseRequest;
import com.xcity.pomelo.request.PVEStageFightRequest;
import com.xcity.pomelo.request.PVEStageListRequest;
import com.xcity.pomelo.request.PVEStageListV2Request;
import com.xcity.pomelo.request.PVEStageRequest;
import com.xcity.pomelo.request.PVEStageUseItemRequest;
import com.xcity.pomelo.request.PVEStageV2Request;
import com.xcity.pomelo.request.PVESweepRequest;
import com.xcity.pomelo.response.HintResponse;
import com.xcity.pomelo.response.PVEAttackResponse;
import com.xcity.pomelo.response.PVEBeAttackedResponse;
import com.xcity.pomelo.response.PVEFullResponse;
import com.xcity.pomelo.response.PVEGetAllBoxResponse;
import com.xcity.pomelo.response.PVEGetStageBoxResponse;
import com.xcity.pomelo.response.PVEGetStarBoxResponse;
import com.xcity.pomelo.response.PVEMoveBlockResponse;
import com.xcity.pomelo.response.PVEStageAreaResponse;
import com.xcity.pomelo.response.PVEStageBoxInfoResponse;
import com.xcity.pomelo.response.PVEStageBuyItemResponse;
import com.xcity.pomelo.response.PVEStageFightResponse;
import com.xcity.pomelo.response.PVEStageListResponse;
import com.xcity.pomelo.response.PVEStageListV2Response;
import com.xcity.pomelo.response.PVEStageResponse;
import com.xcity.pomelo.response.PVEStageUseItemResponse;
import com.xcity.pomelo.response.PVEStageV2Response;
import com.xcity.pomelo.response.PVESweepResponse;
import com.xcity.pomelo.response.Response;

import gnu.trove.map.hash.TIntObjectHashMap;
import naga.x.App;
import naga.x.common.Updatable;
import naga.x.event.Event;
import naga.x.event.EventListener;
import naga.x.game.template.TemplateService;
import naga.x.game.time.TimeUpdater;
import naga.x.net.Session;
import naga.x.net.annotation.OPHandler;
import naga.x.net.impl.pomelo.annotation.PomeloOP;
import naga.x.service.Service;
import naga.x.service.ServiceException;

/**
 * 这个类只有{@link PomeloRoute#PVE_STAGE_V2}, {@link PomeloRoute#PVE_STAGES_V2}, {@link PomeloRoute#PVE_GET_STAGE_BOX}, {@link PomeloRoute#PVE_GET_STAR_BOX}
 * , {@link PomeloRoute#PVE_GET_ALL_BOX}协议有用<br/>
 * 其他战斗相关的协议请参考{@link CombatService}
 * @author yang.li
 * @see CombatService
 *
 */
@OPHandler
public class PVEService implements Service, EventListener, Updatable, ISystem {

	protected List<StageTemplate> templates;
	@Deprecated
	protected Map<Long, PVEBattle> battles = new ConcurrentHashMap<Long, PVEBattle>(128);
	protected int maxNormalPage;	//普通关 大关总数
	
	public static final int CARRY_EMPLOYEE_MAX_NUM = 4; // 最多只能携带4个员工
	@Deprecated
	public static final int NUM_OF_PER_PAGE = 10;//12; // 每张大地图12个关卡
	protected static final Logger LOG = LoggerFactory.getLogger(PVEService.class);
	
	protected TIntObjectHashMap<List<StagePageTemplate>> area2pageTemp = new TIntObjectHashMap<List<StagePageTemplate>>();
	
	@Override
	public void startup() throws ServiceException {
		TemplateService service = App.getApp().getServiceManager().get(TemplateService.class);
		TIntObjectHashMap<Integer> normalPage2count = new TIntObjectHashMap<>();
		TIntObjectHashMap<Integer> heroPage2count = new TIntObjectHashMap<>();
		templates = service.getTemplatesList(StageTemplate.class);
		for (int i = 0; i < templates.size(); i++) {
			StageTemplate t = templates.get(i);
			if (t.getId() == StageTemplate.FRESH_TEMPLATE.getId()) { // 从列表模板中移除新手引导关卡
				templates.remove(i);
				i--;
//				break;
				continue;
			}else{
				if(t.getType() == PVEManager.STAGE_TYPE_NORMAL || t.getType() == PVEManager.STAGE_TYPE_BOSS){
					int curPage = t.getPage();//((t.getId() - StageTemplate.MIN_ID - 1) / NUM_OF_PER_PAGE) + 1;//从1开始
					int count = 0;
					if(normalPage2count.containsKey(curPage)){
						count = normalPage2count.get(curPage);
						count++;
					}
					normalPage2count.put(curPage, count);
//					if(bossIdList == null){
//						bossIdList = new ArrayList<Integer>();
//					}
//					bossIdList.add(t.getId());
//					normalPage2count.put(curPage, bossIdList);
				}else if(t.getType() == PVEManager.STAGE_TYPE_HERO){
					int curPage = t.getPage();
					int count = 0;
					if(heroPage2count.containsKey(curPage)){
						count = heroPage2count.get(curPage);
						count++;
					}
					count++;
					heroPage2count.put(t.getPage(), count);
//					if(idList == null){
//						idList = new ArrayList<Integer>();
//					}
//					idList.add(t.getId());
//					heroPage2count.put(t.getPage(), idList);
				}
			}
		}
		maxNormalPage = normalPage2count.size();//(normalCount/*templates.size()*/ + NUM_OF_PER_PAGE - 1) / NUM_OF_PER_PAGE;
		if (StageTemplate.MAX_NORMAL_PAGE != maxNormalPage) {
			throw new ServiceException("StageTemplate#MAX_NORMAL_PAGE != PVEService#maxNormalPage");
		}
		int[] keys = heroPage2count.keys();
		if(keys.length != maxNormalPage){
			throw new ServiceException("普通大关与精英大关数量不符合");
		}
		for(int i = 0;i < keys.length; i++){
			if(keys[i] > maxNormalPage){
				throw new ServiceException("普通大关与精英大关数量不符合");
			}
//			List<Integer> bossIds = normalPage2count.get(keys[i]);
//			List<Integer> heroIds = heroPage2count.get(keys[i]);
//			int size = heroIds.size();
//			if(size != bossIds.size()){
//				throw new ServiceException(keys[i] + "页普通关卡BOSS数量与精英关卡数量不符合");
//			}
//			for(int j = 0; j < size; j++){
//				StageTemplate heroT = service.get(StageTemplate.class, heroIds.get(j));
//				heroT.trySetPreviousId(bossIds.get(j));
//			}
		}
		List<StagePageTemplate> pageTempList = service.getTemplatesList(StagePageTemplate.class);
		for(int i = 0, size = pageTempList.size(); i < size; i++){
			StagePageTemplate temp = pageTempList.get(i);
			List<StagePageTemplate> tempList;
			if(area2pageTemp.containsKey(temp.getArea())){
				tempList = area2pageTemp.get(temp.getArea());
			}else{
				tempList = new ArrayList<StagePageTemplate>();
				area2pageTemp.put(temp.getArea(), tempList);
			}
			tempList.add(temp);
		}
		
		
		App.getApp().getEventManager().register(this);
		App.getApp().getUpdater().addAsync(this);
	}

	@Override
	public void shutdown() throws ServiceException {
	}

	@Override
	public String getId() {
		return getClass().getName();
	}
	
	@Deprecated
//	@PomeloOP(PomeloRoute.PVE_STAGES)
	protected void requestList(Session session, PVEStageListRequest req) {
		Player player = session.getClient();
		int page = req.getPage() < 0 ? player.getPveStages().getCurrentPage((byte)0) : req.getPage();
		List<PVEStage> stages = player.getPveStages().getStages(page, 0);
		PVEStageListResponse res = new PVEStageListResponse(req.getSerial(), page, maxNormalPage, player, stages);
		session.send(res);
	}
	
	@PomeloOP(PomeloRoute.PVE_AREA)
	protected void requestStageArea(Session session, PVEStageAreaRequest req){
		Player player = session.getClient();
		int area = req.getArea();
		byte type = req.getType();
		int reachPage = player.getPveStages().getCurrentPage(type);//0~X
		List<PVEStage> resultStages = player.getPveStages().getStages(reachPage, type);
		if(resultStages.get(resultStages.size() - 1).isPass()){
			//reachPage最后一关已过
			if(reachPage < maxNormalPage - 1){
				//不是最后page
				reachPage++;
			}
		}
		int maxArea = App.getApp().getServiceManager().get(TemplateService.class).get(StagePageTemplate.class, maxNormalPage).getArea();
		int reachArea = App.getApp().getServiceManager().get(TemplateService.class).get(StagePageTemplate.class, reachPage + 1).getArea();
		if(area == -1){
			//请求最大的
			area = reachArea;
		}
		List<StagePageTemplate> list = area2pageTemp.get(area);
		if(list == null || list.size() <= 0){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_MAP_INFO));
			return;
		}
		List<Ranking> ranklist = null;
		RankingListEnum rle = RankingListEnum.forType((byte) 9);
		if(rle != null){
			RankingList rl = rle.instance;
			ranklist = rl.getEntries(player);
		}
		player.send(new PVEStageAreaResponse(req.getSerial(), reachPage, reachArea, maxArea, area, req.getType(), list, ranklist));
	}

	@PomeloOP(PomeloRoute.PVE_STAGES_V2)
	protected void requestListV2(Session session, PVEStageListV2Request req){
		Player player = session.getClient();
		byte type = req.getType();
		if(type != 0 && type != 1){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAGE));
			return;
		}
		int page = req.getPage() < 0 ? player.getPveStages().getCurrentPage((byte)type) : req.getPage();
		List<PVEStage> resultStages = player.getPveStages().getStages(page, type);
		
		if(req.getPage() < 0 && resultStages.get(resultStages.size() - 1).isPass()){
			if(page < maxNormalPage - 1){
				//本大关最后一关 加一页
				page++;
				resultStages = player.getPveStages().getStages(page, type);
			}
		}
		
//		List<PVEStage> normalStages = player.getPveStages().getStages(page, 0);
//		List<PVEStage> heroStages = player.getPveStages().getStages(page, 1);
//		int[] getStar = new int[2];
		int getStar = player.getPveStages().getStagesStar(resultStages);
//		getStar[0] = player.getPveStages().getStagesStar(normalStages);
//		getStar[1] = player.getPveStages().getStagesStar(heroStages);
		byte[] gotStarBox = new byte[StagePageTemplate.MAX_BOX_COUNT];//2 * 
//		for(int i = 0; i < 2; i++){
//		}
		for(int j = 0; j < StagePageTemplate.MAX_BOX_COUNT; j++){
			if(player.getPveStages().getStarBoxId(page, type, j) > 0){
				//有宝箱
				if(player.getPveStages().isGotStarBox(page, type, j)){
					gotStarBox[j] = 1;// + i * StagePageTemplate.MAX_BOX_COUNT
				}else{
					gotStarBox[j] = 0;// + i * StagePageTemplate.MAX_BOX_COUNT
				}
			}else{
				gotStarBox[j] = -1;// + i * StagePageTemplate.MAX_BOX_COUNT
			}
		}
		StagePageTemplate temp = App.getApp().getServiceManager().get(TemplateService.class).get(StagePageTemplate.class, page + 1);
		int heroPage = player.getPveStages().getCurrentPage((byte) 1);
		int normalPage = player.getPveStages().getCurrentPage((byte) 0);
		PVEStageListV2Response res = new PVEStageListV2Response(req.getSerial(), page, type, maxNormalPage, heroPage, normalPage, temp, player, resultStages, getStar, gotStarBox);
		session.send(res);
	}

	@Deprecated
//	@PomeloOP(PomeloRoute.PVE_STAGE)
	protected void requestStage(Session session, PVEStageRequest req) {
		Player player = session.getClient();
		PVEStage stage = player.getPveStages().getStage(req.getId());
		if (stage == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAGE));
			return;
		}
		PVEStageResponse res = new PVEStageResponse(req.getSerial(), player, stage);
		session.send(res);
	}
	
	@PomeloOP(PomeloRoute.PVE_STAGE_V2)
	protected void requestStageV2(Session session, PVEStageV2Request req){
		Player player = session.getClient();
		PVEStage stage = player.getPveStages().getStage(req.getId());
		if (stage == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAGE));
			return;
		}
		PVEStageV2Response res = new PVEStageV2Response(req.getSerial(), player, stage);
		session.send(res);
	}

	@PomeloOP(PomeloRoute.PVE_GET_STAGE_BOX)
	protected void requestGetStageBox(Session session, PVEGetStageBoxRequest req){
		Player player = session.getClient();
		PVEStage stage = player.getPveStages().getStage(req.getId());
		if(stage == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_BOX));
			return;
		}
		byte state = stage.getStageBoxState();
		if(state == 0){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_BOX));
			return;
		}else if(state == 1){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_PASS));
			return;
		}else if(state == 3){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_GOT_BOX));
			return;
		}
		
		//TODO 关卡宝箱奖励
		DropGroupTemplate dropTemp = App.getApp().getServiceManager().get(TemplateService.class).get(DropGroupTemplate.class, stage.getTemplate().getStageBoxId());
		DropGroup drop = dropTemp.getDrop();
		BoxDropListener listener = new BoxDropListener();
		drop.drop(Drop.RND, player, Cause.STAGE_BOX, listener);
		stage.setGotBox((byte) 1);
		
		PVEGetStageBoxResponse response = new PVEGetStageBoxResponse(req.getSerial(), stage.getId(), stage.getStageBoxState(), listener.getItems(), listener.getMoney(), listener.getStone());
		player.send(response);
		LOG.info("[GOTSTAGEBOX]ID[{}]INDEX[-1]GOT[{}]STAGE[{}]", player.getId(), stage.getGotBox(), stage.getId());
	}
	
	@PomeloOP(PomeloRoute.PVE_GET_STAR_BOX)
	public void requestGetStarBox(Session session, PVEGetStarBoxRequest req){
		Player player = session.getClient();
		int page = req.getPage();
		if(page < 0 || page >= maxNormalPage){
			//没有宝箱信息
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_ERROR_BOX));
			return;
		}
		int phase = req.getBoxIndex();
		if(phase < 0 || phase >= StagePageTemplate.MAX_BOX_COUNT){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_ERROR_BOX));
			return;
		}
		byte type = req.getType();
		if(type != 0 && type != 1){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_ERROR_BOX));
			return;
		}
		
		List<PVEStage> stageLists = player.getPveStages().getStages(page, type);
		int needStar = player.getPveStages().getNeedStarByPhase(page, phase, type);
		int starCount = player.getPveStages().getStagesStar(stageLists);
		if(starCount < needStar){
			player.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.PVE_STAGE_NEED_STAR, needStar - starCount)));
			return;
		}

		int boxid = player.getPveStages().getStarBoxId(page, type, phase);
		if(boxid <= 0){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_BOX_GET));
			return;
		}
		if(player.getPveStages().isGotStarBox(page, type, phase)){
			//已领取
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_GOT_BOX));
			return;
		}
		StagePageTemplate boxTemp = App.getApp().getServiceManager().get(TemplateService.class).get(StagePageTemplate.class, page + 1);
		DropGroupTemplate dropTemp = App.getApp().getServiceManager().get(TemplateService.class).get(DropGroupTemplate.class, boxTemp.getStarBoxId()[phase + type * StagePageTemplate.MAX_BOX_COUNT]);
		Drop drop = dropTemp.getDrop();
		BoxDropListener listener = new BoxDropListener();
		drop.drop(Drop.RND, player, Cause.STAR_BOX, listener);
		player.getPveStages().setGotStarBox(page, type, phase);
		
		byte boxState = -1;
		if(player.getPveStages().getStarBoxId(page, type, phase) > 0){
			//有宝箱
			if(player.getPveStages().isGotStarBox(page, type, phase)){
				boxState = 1;//
			}else{
				boxState = 0;//
			}
		}
		
		PVEGetStarBoxResponse response = new PVEGetStarBoxResponse(req.getSerial(), page, type, phase, listener.getItems(), listener.getMoney(), listener.getStone(), boxState);
		LOG.info("[GOTSTARBOX]ID[{}]PAGE[{}]TYPE[{}]PHASE[{}]", player.getId(), page, type, phase);
		player.send(response);
	}

	@PomeloOP(PomeloRoute.PVE_GET_ALL_BOX)
	protected void requestGetAllBox(Session session, PVEGetAllBoxRequest req){
		Player player = session.getClient();
		int page = req.getPage();
		if(page < 0 || page >= maxNormalPage){
			//没有宝箱信息
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_ERROR_BOX));
			return;
		}
		byte type = req.getType();
		if(type != 0 && type != 1){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_ERROR_BOX));
			return;
		}
		List<PVEStage> stageList = player.getPveStages().getStages(page, type);
		BoxDropListener listener = new BoxDropListener();
		boolean succ = false;
		List<Integer> stageIds = new ArrayList<>();
		TemplateService ts = App.getApp().getServiceManager().get(TemplateService.class);
		for(int i = 0;i < stageList.size(); i++){
			PVEStage stage = stageList.get(i);
			if(stage.getStageBoxState() == 2){
				//可领未领
				DropGroupTemplate dropGropTemp = ts.get(DropGroupTemplate.class, stage.getTemplate().getStageBoxId());
				if(dropGropTemp != null){
					Drop drop = dropGropTemp.getDrop();
					if(drop.drop(Drop.RND, player, Cause.ALL_BOX, listener)){
						stage.setGotBox((byte) 1);
						stageIds.add(stage.getId());
						succ = true;
					}
				}
			}
		}
		byte starBoxCount = 0;
		List<Byte> boxGotIndex = new ArrayList<Byte>();
		int starCount = player.getPveStages().getStagesStar(stageList);
		for(int i = 0;i < StagePageTemplate.MAX_BOX_COUNT; i++){
			int boxid = player.getPveStages().getStarBoxId(page, type, i);
			if(boxid > 0){
				if(!player.getPveStages().isGotStarBox(page, type, i)){
					int needStar = player.getPveStages().getNeedStarByPhase(page, i, type);
					if(starCount >= needStar){
						DropGroupTemplate dropGropTemp = ts.get(DropGroupTemplate.class, boxid);
						if(dropGropTemp != null){
							Drop drop = dropGropTemp.getDrop();
							if(drop.drop(Drop.RND, player, Cause.ALL_BOX, listener)){
								player.getPveStages().setGotStarBox(page, type, i);
								starBoxCount++;
								boxGotIndex.add((byte) i);
								succ = true;
							}
						}
					}
				}
			}
		}
		byte[] states = new byte[StagePageTemplate.MAX_BOX_COUNT];
		for(int i = 0; i < StagePageTemplate.MAX_BOX_COUNT; i++){
			if(player.getPveStages().getStarBoxId(page, type, i) > 0){
				if(player.getPveStages().isGotStarBox(page, type, i)){
					states[i] = 1;
				}else{
					states[i] = 0;
				}
			}else{
				states[i] = -1;
			}
		}
		if(!succ){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_BOX_GET));
			return;
		}
		player.send(new PVEGetAllBoxResponse(req.getSerial(), page, type, boxGotIndex, stageIds, starBoxCount, listener.getMoney(), listener.getStone(), listener.getItems()));
		LOG.info("[GOTALLEBOX]ID[{}]PAGE[{}]TYPE[{}]STARBOX[{}]STAGEBOX[{}]", player.getId(), page, type, boxGotIndex.toString(), stageIds.toString());
	}
	
	@PomeloOP(PomeloRoute.PVE_SWEEP)
	protected void requestSweep(Session session, PVESweepRequest req){
		Player player = session.getClient();
		PVEStage stage = player.getPveStages().getStage(req.getId());
		if (stage == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAGE));
			return;
		}
		if(stage.getStar() < 3){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAR));
			return;
		}
		if(stage.getTemplate().getLevelLimit() > player.getLevel()){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_LEVEL_LIMIT));
			return;
		}
		int requestCount = req.getCount();
		int vipSweepCount = VipUtils.getTemplate(player.getVipLvl()).getSweepCount();
		if(requestCount > vipSweepCount){
			int needVip = VipUtils.getNextVipLevel(player.getVipLvl(), requestCount);
			if(needVip > -1){
				player.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.PVE_STAGE_VIP_NEXTLVL, needVip, requestCount)));
				return;
			}else{
				player.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.PVE_STAGE_VIP_LVL, vipSweepCount)));
				return;
			}
		}
		if(stage.getLeftTimes(player) < requestCount){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NOT_ENOUGH_COUNT));
			return;
		}
		int needStr = stage.getTemplate().getCostStr() * requestCount;
		if(needStr < 0 || player.getVigour() < needStr){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_VIGOUR));//PVE_STAGE_NO_STRENTH
			return;
		}
		//发奖励
		List<Drop> allDrops = stage.getTemplate().getRewardsDrop();
		List<Drop> resultDropLit = new ArrayList<Drop>();
		List<PVEStageDropListener> listenerList = new ArrayList<PVEStageDropListener>();
//		long[] employeeIds = CombatUtils.getCombatFormation(player, true);
//		List<Employee> employees = new ArrayList<Employee>(employeeIds.length);
//		for (long eid : employeeIds) {
//			Employee e = eid != 0L ? player.getEmployees().get(eid) : null;
//			employees.add(e);
//		}
		List<Employee> employees = Collections.emptyList();
		Formation f = player.getFormations().get(Formation.TYPE_NORMAL);
		if (f != null) {
			employees = Arrays.asList(f.getUnits());
		}
		PVEUtils.calcPVEStageDrop(player, employees, stage, resultDropLit, allDrops, 0, requestCount, listenerList, Cause.PVE_SWEEP);
		//扣体力
//		player.decStrength(needStr, Cause.PVE_SWEEP);
		player.decVigour(needStr, Cause.PVE_SWEEP);
		//扣次数
		for(int i = 0; i < requestCount; i++){
			stage.end(stage.getStar());
		}
		int leftCount = stage.getLeftTimes(player);
		int canSweepCount = leftCount;
		if(stage.getTemplate().getCostStr() > 0){
			int strCount = player.getVigour() / stage.getTemplate().getCostStr();
			if(canSweepCount > strCount){
				canSweepCount = strCount;
			}
		}
		List<Integer> sweepCountList = VipUtils.getSweepCountList(player.getVipLvl(), canSweepCount);
		int triggerFactor = 0;
		triggerFactor = stage.getTemplate().getShowShop();
		player.send(new PVESweepResponse(req.getSerial(), stage.getId(), leftCount, sweepCountList, listenerList));
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_SWEEP_DONE, player, triggerFactor, stage.getTemplate().getType(), requestCount);
		LOG.info("[PVE SWEEP]ID[{}]STAGE[{}]COUNT[{}]", player.getId(), stage.getId(), requestCount);
	}
	
	@PomeloOP(PomeloRoute.PVE_FULL)
	protected void requestPVEFull(Session session, PVEFullRequest req){
		Player player = session.getClient();
		PVEStage stage = player.getPveStages().getStage(req.getId());
		if(stage == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAGE));
			return;
		}
		byte type = (byte) (stage.getTemplate().getType() == PVEManager.STAGE_TYPE_HERO? 1 : 0);
		int resetCount = stage.getTodayResetCount(player, type);
		int vipCount = 0;//VipUtils.getTemplate(player.getVipLvl()).getFullNormalStage();
		BuyCount bc;
		if(stage.getTemplate().getType() == PVEManager.STAGE_TYPE_HERO){
			vipCount = VipUtils.getTemplate(player.getVipLvl()).getFullHeroStage();
			bc = BuyCount.PVE_HERO_RESET;
		}else{
			vipCount = VipUtils.getTemplate(player.getVipLvl()).getFullNormalStage();
			bc = BuyCount.PVE_NORMAL_RESET;
		}
		if(vipCount - resetCount <= 0){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_RESET_COUNT));
			return;
		}
		int leftTime = stage.getLeftTimes(player);
		if(leftTime == stage.getTemplate().getNumOfPerDay() || stage.getTemplate().getNumOfPerDay() == 0){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_NEED_RESET));
			return;
		}
//		int costStone = App.getApp().getServiceManager().get(BuyCountService.class).getCostStone(player, stage.getTemplate().getType() == PVEManager.STAGE_TYPE_HERO? BuyCountService.BUY_COUNT_TYPE_HERO : BuyCountService.BUY_COUNT_TYPE_NORMAL, resetCount, vipCount);
		int costStone = bc.getCostStone(player, resetCount);
		if(!player.costStone(costStone, Cause.PVE_BUY_RESET)){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_RESET_NO_STONE));
			return;
		}
		stage.setFoughtTimesToday(0);
//		if(type == 1){
//		}else{
//			if(stage.getFoughtTimesToday() > 10){
//				stage.setFoughtTimesToday(stage.getFoughtTimesToday() - 10);
//			}else{
//				stage.setFoughtTimesToday(0);
//			}
//		}
		resetCount++;
		stage.setResetCount(resetCount);
		stage.setResetCountDay(TimeUpdater.getInstance().today());
//		if(type == 0){
//			player.getPool().put(PlayerPool.PROPERTY_PVE_FULL_NORMAL_COUNT, resetCount);
//			player.getPool().put(PlayerPool.PROPERTY_PVE_FULL_NORMAL_DAY, TimeUpdater.getInstance().today());
//		}else{
//			player.getPool().put(PlayerPool.PROPERTY_PVE_FULL_HERO_COUNT, resetCount);
//			player.getPool().put(PlayerPool.PROPERTY_PVE_FULL_HERO_DAY, TimeUpdater.getInstance().today());
//		}

		int newLeftTime = stage.getLeftTimes(player);
		player.send(new PVEFullResponse(req.getSerial(), player, stage));
		LOG.info("[PVEFULL]ID[{}]INDEX[-1]OLD[{}]NEW[{}]", player.getId(), leftTime, newLeftTime);
	}
	
	@PomeloOP(PomeloRoute.PVE_GET_BOX_INFO)
	protected void requestBoxInfo(Session session, PVEStageBoxInfoRequest req){
		Player player = session.getClient();
		int type = req.getRequestType();
		int dropGroupId = 0;
		if(type == 0){
			int stageId = req.getId();
			PVEStage pveStage = player.getPveStages().getStage(stageId);
			if(pveStage == null){
				player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_CANT_FIND_STAGE_BOX));
				return;
			}
			dropGroupId = pveStage.getTemplate().getStageBoxId();
		}else if(type == 1){
			StagePageTemplate temp = App.getApp().getServiceManager().get(TemplateService.class).get(StagePageTemplate.class, req.getPage() + 1);
			int isHero = req.getIsHero();
			if(temp == null){
				player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_CANT_FIND_STAR_BOX));
				return;
			}
//			int needStart = 0;
			int index = req.getId() + isHero * 3;
			if(index > -1 && index < temp.getStarBoxId().length){
				dropGroupId = temp.getStarBoxId()[index];
//				needStart = temp.getNeedStar()[req.getId()];
			}else{
				player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_CANT_FIND_STAR_BOX));
				return;
			}
			
//			int totalStar = player.getPveStages().getStagesStar(player.getPveStages().getStages(req.getPage(), isHero));
		}
		if(dropGroupId <= 0){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_ERROR_BOX));
			return;
		}
		DropGroupTemplate groupTemp = App.getApp().getServiceManager().get(TemplateService.class).get(DropGroupTemplate.class, dropGroupId);
		if(groupTemp == null){
			player.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_ERROR_BOX));
			return;
		}
		int money = groupTemp.getMinGold();
		int stone = groupTemp.getMinStone();
//		int len = groupTemp.getItems()==null?0:groupTemp.getItems().length;
//		len = (len + 3) / 4;
//		int[] itemIds = new int[len];
//		int[] itemCounts = new int[len];
//		for(int i = 0; i < len; i++){
//			itemIds[i] = groupTemp.getItems()[i * 4];
//			itemCounts[i] = groupTemp.getItems()[i * 4 + 1];
//		}
		List<Integer> itemIds = new ArrayList<Integer>();
		List<Integer> itemCounts = new ArrayList<Integer>();
		List<WeightDrop> list = groupTemp.getDrop().getWeightDrops();
		int size = list.size();
		for(int i = 0;i < size; i++){
			Drop drop = list.get(i);
			ItemDrop itemDrop = (ItemDrop)drop;
			if(itemDrop != null){
				if(itemDrop.getCount() > 0){
					itemIds.add(itemDrop.getId());
					itemCounts.add(itemDrop.getCount());
				}
			}
		}
		List<Drop> fixList = groupTemp.getDrop().getFixedDrops();
		size = fixList.size();
		for(int i = 0;i < size; i++){
			Drop drop = fixList.get(i);
			if(drop instanceof ItemDrop){
				ItemDrop itemDrop = (ItemDrop)drop;
				if(itemDrop != null){
					if(itemDrop.getCount() > 0){
						itemIds.add(itemDrop.getId());
						itemCounts.add(itemDrop.getCount());
					}
				}
			}
		}
		player.send(new PVEStageBoxInfoResponse(req.getSerial(), req.getRequestType(), money, stone, itemIds, itemCounts));
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_STAGE_FIGHT)
	protected void requestFight(Session session, PVEStageFightRequest req) {
		Player player = session.getClient();
		if (battles.containsKey(player.getId())) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_FIGHTING));
			return;
		}
		PVEStage stage = player.getPveStages().getStage(req.getId());
		if (stage == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAGE));
			return;
		}
		if (stage.getTemplate().getLevelLimit() > player.getLevel()) {
			session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.PVE_STAGE_LEVEL_LIMIT, stage.getTemplate().getLevelLimit())));
			return;
		}
		PVEStage previous = player.getPveStages().findPreviousStage(stage);
		if (previous != null && previous.getStar() <= 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_PREVIOUS_STAGE_NOT_PASS));
			return;
		}
		if (stage.getLeftTimes(player) == 0) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_LEFT_TIMES));
			return;
		}
		// 携带员工
		long[] employeeIds = req.getEmployees();
		List<Employee> carryEmployees = Collections.emptyList();//player.getEmployees().filter(State.PRE_PVE);
		if (employeeIds != null) {
			int len = employeeIds.length;
			if (len > CARRY_EMPLOYEE_MAX_NUM) {
				session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.PVE_CARRY_EMPLOYEE_NUM_EXCEED, CARRY_EMPLOYEE_MAX_NUM)));
				return;
			}
			carryEmployees = new ArrayList<Employee>(len);
			for (long eid : employeeIds) {
				Employee employee = player.getEmployees().get(eid);
				if (employee == null) {
					session.send(new HintResponse(req.getSerial(), MessageConst.EMPLOYEE_NOT_EXIST));
					return;
				}
//				if (employee.getState() != State.PRE_PVE) {
//					session.send(new HintResponse(req.getSerial(), MessageConst.PVE_EMPLOYEE_STATE_ERROR));
//					return;
//				}
				if (employee.getEnergy() < 1) {
					session.send(new HintResponse(req.getSerial(), MessageFormat.format(MessageConst.EMPLOYEE_ENERGY_NOT_ENOUGH, employee.getName())));
					return;
				}
				carryEmployees.add(employee);
			}
		}
		
		if (stage.getTemplate().getCostStr() > 0 && !player.decStrength(stage.getTemplate().getCostStr(), Cause.PVE_FIGHT)) {
			session.send(new HintResponse(req.getSerial(), MessageConst.STR_NOT_ENOUGH));
			return;
		}
		for (int i = 0; i < carryEmployees.size(); i++) {
//			carryEmployees.get(i).decEnergy(1, Cause.PVE_FIGHT);
		}
		
		List<ItemInfo> canCarrys = stage.getTemplate().getCanCarryItemsList();
		// 携带道具
		List<ItemInfo> carryItems = canCarrys.isEmpty() ? Collections.emptyList() : new ArrayList<ItemInfo>(canCarrys.size());
		for (int i = 0, size = canCarrys.size(); i < size; i++) {
			ItemInfo canCarryItem = canCarrys.get(i);
			int count = player.getBag().countOf(canCarryItem.getId()); // 背包中实际数量
			carryItems.add(new ItemInfo(canCarryItem.getId(), count < canCarryItem.getCount() ? count : canCarryItem.getCount()));
		}
		
		PVEBattle battle = new PVEBattle(player, stage, carryEmployees, carryItems);
		battles.put(player.getId(), battle);
		PVEStageFightResponse res = new PVEStageFightResponse(req.getSerial(), player, stage, carryItems, carryEmployees, battle);
		session.send(res);
		App.getApp().getEventManager().addEvent(GameEvents.EVENT_USE_SYSTEM, player, getSystemId(), 1);
		LOG.info("[PVE TRY]ID[{}]STAGE[{}]", player.getId(), stage.getId());
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_STAGE_FIGHT_BEGIN)
	protected void requestFightBegin(Session session, PVEStageFightBeginRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.get(player.getId());
		if (battle == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE));
			return;
		}
		battle.begin();
		session.send(new Response(req.getSerial()));
		LOG.info("[PVE BEGIN]ID[{}]STAGE[{}]", player.getId(), battle.stage.getId());
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_STAGE_END)
	protected void requestFightEnd(Session session, PVEStageFightEndRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.remove(player.getId());
		if (battle == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE));
			return;
		}
		battle.end(req, Cause.PVE_END);
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_STAGE_FIGHT_PAUSE)
	protected void requestFightPause(Session session, PVEStageFightPauseRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.get(player.getId());
		if (battle == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE));
			return;
		}
		String error = battle.pause();
		if (error != null) {
			session.send(new HintResponse(req.getSerial(), error));
			return;
		}
		session.send(new Response(req.getSerial()));
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_STAGE_FIGHT_GO_ON)
	protected void requestFightGoOn(Session session, PVEStageFightGoOnRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.get(player.getId());
		if (battle == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE));
			return;
		}
		String error = battle.goOn();
		if (error != null) {
			session.send(new HintResponse(req.getSerial(), error));
			return;
		}
		session.send(new Response(req.getSerial()));
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_STAGE_BUY_ITEM)
	protected void requestBuyItem(Session session, PVEStageBuyItemRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.get(player.getId());
		PVEStage stage;
		ItemInfo item = null;
		if (battle != null) {
			item = battle.getItem(req.getItemId());
			stage = battle.stage;
		} else {
			stage = player.getPveStages().getStage(req.getId());
		}
		if (stage == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_STAGE_NO_STAGE));
			return;
		}
		ItemInfo template = stage.getTemplate().getCanCarryItem(req.getItemId());
		if (template == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_CAN_NOT_BUY_THE_ITEM));
			return;
		}
		int c = item != null ? item.getCount() : player.getBag().countOf(req.getItemId()); // 统计已有数量
		if (c >= template.getCount()) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_CAN_NOT_BUY_ITEM_ENOUGH));
			return;
		}
		ShopItemTemplate shopItemTemplate = App.getApp().getServiceManager().get(TemplateService.class).get(ShopItemTemplate.class, req.getItemId());
		if (shopItemTemplate == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_CAN_NOT_BUY_THE_ITEM));
			return;
		}
		// 修正可购买数量
		int buyCount = req.getCount() + c <= template.getCount() ? req.getCount() : template.getCount() - c;
		Currency currency = shopItemTemplate.getPriceType();
		if (!player.cost(currency, shopItemTemplate.getPrice()/*原价购买*/ * buyCount, Cause.PVE_BUY)) {
			session.send(new HintResponse(req.getSerial(), currency == Currency.GOLD ? MessageConst.GOLD_NOT_ENOUGH : MessageConst.STONE_NOT_ENOUTH));
			return;
		}
		player.getBag().addItemWithoutException(req.getItemId(), buyCount, Cause.PVE_BUY);
		if (item != null) { // 战斗中购买需要修正该物品数量
			item.setCount(item.getCount() + buyCount);
		}
		session.send(new PVEStageBuyItemResponse(req.getSerial(), stage.getId(), req.getItemId(), buyCount));
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_STAGE_FIGHT_USE_ITEM)
	protected void requestUseItem(Session session, PVEStageUseItemRequest req) {
		Player player = session.getClient();
		if (req.getCount() <= 0
				|| App.getApp().getServiceManager().get(TemplateService.class).get(ItemTemplate.class, req.getItemId()) == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.ITEM_NOT_ENOUGH2));
			return;
		}
		PVEBattle battle = battles.get(player.getId());
		if (battle == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE));
			return;
		}
		try {
			ItemInfo item = battle.useItem(req.getItemId(), req.getCount());
			session.send(new PVEStageUseItemResponse(req.getSerial(), item.getId(), item.getCount()));
		} catch (PVEException e) {
			session.send(new HintResponse(req.getSerial(), e.getMessage()));
		}
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_ATTACK)
	protected void requestAttack(Session session, PVEAttackRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.get(player.getId());
		if (battle == null) {
			session.send(new Response(req.getSerial())/*new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE)*/);
			return;
		}
		PVEAttackResponse res;
		PlayerBattler src = battle.getSource();
		NPCBattler dest = battle.getTarget();
		try {
			battle.attack(req);
			res = new PVEAttackResponse(req.getSerial(), true, req.getEid(), req.getSkillId(), src.getHp(), dest.getHp(), null, src.getAttack(), dest.getAttack(), battle.syncStep);
		} catch (BattleException e) {
			res = new PVEAttackResponse(req.getSerial(), false, req.getEid(), req.getSkillId(), src.getHp(), dest.getHp(), e.getMessage(), src.getAttack(), dest.getAttack(), battle.syncStep);
		}
		session.send(res);
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_BE_ATTACKED)
	protected void requestBeAttacked(Session session, PVEBeAttackedRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.get(player.getId());
		if (battle == null) {
			session.send(new Response(req.getSerial())/*new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE)*/);
			return;
		}
		try {
			battle.defense();
		} catch (BattleException e) {}
		EmployeeSkill skill = battle.getTriggeredSkill();
		long eid = 0;
		int skillId = 0;
		if (skill != null) {
			eid = skill.getOwner().getId();
			skillId = skill.getId();
		}
		PVEBeAttackedResponse res = new PVEBeAttackedResponse(req.getSerial(), battle.getSource().getHp(), battle.getTarget().getHp(), eid, skillId, battle.syncStep);
		session.send(res);
	}
	
	@Deprecated
	@PomeloOP(PomeloRoute.PVE_MOVE_BLOCK)
	protected void requestMoveBlock(Session session, PVEMoveBlockRequest req) {
		Player player = session.getClient();
		PVEBattle battle = battles.get(player.getId());
		if (battle == null) {
			session.send(new HintResponse(req.getSerial(), MessageConst.PVE_HAS_NO_BATTLE));
			return;
		}
		battle.moveStep();
		session.send(new PVEMoveBlockResponse(req.getSerial(), battle.getSource().getHp(), battle.getTarget().getHp(), false));
	}

	@Override
	public int[] getEventTypes() {
		return new int[] { GameEvents.EVENT_PLAYER_LOGIN, GameEvents.EVENT_PLAYER_LOGOUT };
	}

	@Override
	public void handleEvent(Event event) {
		switch (event.getType()) {
			case GameEvents.EVENT_PLAYER_LOGIN:
				playerLogin(event.getParameter());
				break;
			case GameEvents.EVENT_PLAYER_LOGOUT:
				playerLogout(event.getParameter());
				break;
		}
	}
	
	private void playerLogin(Player player) {
		List<PVEStage> stages = player.getPveStages().getStages();
		int oldCount = player.getPveStages().getStarBoxLength();
		if (stages.size() != templates.size()) {
			player.getPveStages().init(templates);
		}
		if (oldCount != maxNormalPage) {
			player.getPveStages().resetStarBox(maxNormalPage);
		}
	}
	
	private void playerLogout(Player player) {
		PVEBattle battle = battles.remove(player.getId());
		if (battle != null) {
			battle.end(Cause.LOGOUT);
		}
	}

	@Override
	public boolean update() {
		if (battles.isEmpty()) {
			return true;
		}
		Iterator<Entry<Long, PVEBattle>> itr = battles.entrySet().iterator();
		while (itr.hasNext()) {
			Entry<Long, PVEBattle> e = itr.next();
			PVEBattle battle = e.getValue();
			if (battle.isEnd()) {
				battle.end(Cause.TIME_OUT);
				itr.remove();
			}
		}
		return true;
	}

	@Override
	public int getSystemId() {
		return SYS_PVE_STAGE;
	}
	
	

}
